﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UIT.Controls.Containers;
using UIT.Events.Keyboard;
using UIT.Markup;
using System.Xml.Serialization;
using System.Windows.Markup;
using UIT.VisualStates;

namespace UIT.Controls
{
    public abstract class DrawableControl : Control, IDrawableControl
    {
        public override bool IsDrawable
        {
            get
            {
                return true;
            }
        }


        #region IDrawableControl Members

        private Style.Style style;

        [XmlIgnore]
        public Style.Style Style
        {
            get
            {
                if (style == null)
                    style = new Style.Style();
                return style;
            }
            set { style = value; }
        }


        #endregion

        #region IDrawableControl Members

        public Style.Unit Height
        {
            get
            {
                return UIT.Style.Style.GetHeight(this);
            }
            set
            {
                UIT.Style.Style.SetHeight(this, value);
            }
        }

        public Style.Unit Width
        {
            get
            {
                return UIT.Style.Style.GetWidth(this);
            }
            set
            {
                UIT.Style.Style.SetWidth(this, value);
            }
        }

        public Style.Brush Background
        {
            get
            {
                return UIT.Style.Style.GetBackground(this);
            }
            set
            {
                UIT.Style.Style.SetBackground(this, value);
            }
        }

        #endregion

        #region IDrawableControl Members


        public Style.Thickness Margin
        {
            get
            {
                return UIT.Style.Style.GetMargin(this);
            }
            set
            {
                UIT.Style.Style.SetMargin(this, value);
            }
        }

        #endregion
    }

#if !SILVERLIGHT
    [RuntimeNameProperty("Id")]
#endif
    public abstract class Control : IControl
    {
        public Control()
        {
            Events = new Events.Events();
            KeyCommandBindings = new DisposableObservableCollection<IControl, KeyCommandBinding>(this);
        }

        protected void InitializeComponent(Uri xamlSource)
        {
#if !SILVERLIGHT
            RendererManager.Load(this, Application.GetResourceStream(xamlSource));
#else
            throw new NotImplementedException();
#endif
        }

        private void TunnelDataContextChanged()
        {
            if (IsContainer)
            {
                IContainer<IContainer, IControl> self = (IContainer)this;
                if (self.Children == null)
                    return;
                foreach (IControl control in self.Children)
                {
                    if (control != null)
                        control.DataContext = DataContext;
                }
            }
        }

        #region IControl Members

        public string Id
        {
            get;
            set;
        }

        public abstract bool IsContainer { get; }

        public abstract ControlType Type { get; }

        #endregion

        #region IControl Members


        public string StyleKey
        {
            get;
            set;
        }

        private object dataContext;
        private bool manuallySet = false;

        public virtual object DataContext
        {
            get { return dataContext; }
            set
            {
                if (Parent == null || !manuallySet)
                {
                    dataContext = value;
                    manuallySet = Parent == null || Parent.DataContext != null && Parent.DataContext != dataContext;
                    OnPropertyChanged("DataContext");
                }
            }
        }

        #endregion

        #region Visual States

        private IDisposableObservableCollection<IControl, VisualState> visualStates;

        IDisposableObservableCollection<IControl, VisualState> IContainer<IControl, VisualState>.Children
        {
            get
            {
                return VisualStates;
            }
        }

        public IDisposableObservableCollection<IControl, VisualState> VisualStates
        {
            get
            {
                if (visualStates == null)
                    visualStates = new DisposableObservableCollection<IControl, VisualState>(this);
                return visualStates;
            }
        }

        #endregion

        #region INotifyPropertyChanged Members

        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            if (propertyName == "DataContext")
                TunnelDataContextChanged();
            if (PropertyChanged != null)
                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }


        #endregion

        protected IContainer parent;

        [XmlIgnore]
        public IContainer Parent
        {
            get { return parent; }
            set
            {
                if (parent != null)
                    ((IControlContainer)parent).Children.Remove(this);
                parent = value;
                OnPreLoad();
                if (parent != null)
                {
                    DataContext = parent.DataContext;
                    ((IControlContainer)parent).Children.Add(this);
                    OnPostLoad();
                }
                OnPropertyChanged("Parent");
            }
        }

        #region IControl Members

        private bool isEnabled;

        public bool IsEnabled
        {
            get { return isEnabled; }
            set
            {
                isEnabled = value;
                OnPropertyChanged("IsEnabled");
            }
        }

        private bool isVisible;

        public bool IsVisible
        {
            get { return isVisible; }
            set
            {
                isVisible = value;
                OnPropertyChanged("IsVisible");
            }
        }

        #endregion

        #region ISupportInitializeNotification Members

        public event EventHandler Initialized;

        public bool IsInitialized
        {
            get;
            private set;
        }

        #endregion

        #region ISupportInitialize Members

        public void BeginInit()
        {
            Initializing = true;
        }

        public void EndInit()
        {
            Initializing = false;
            IsInitialized = true;
            if (Initialized != null)
                Initialized(this, EventArgs.Empty);
        }

        #endregion

        protected bool Initializing { get; private set; }

        #region IDisposable Members

        public virtual void Dispose()
        {
            Initialized = null;
            Metadata = null;
        }

        #endregion

        #region IControl Members


        public object Metadata
        {
            get;
            set;
        }

        #endregion

        #region IControl Members


        public virtual bool IsDrawable
        {
            get { return false; }
        }

        #endregion

        #region IControl Members


        public Events.Events Events
        {
            get;
            private set;
        }

        #endregion

        #region IControl Members


        public IDisposableObservableCollection<IControl, KeyCommandBinding> KeyCommandBindings
        {
            get;
            private set;
        }

        IDisposableObservableCollection<IControl, KeyCommandBinding> IContainer<IControl, KeyCommandBinding>.Children
        {
            get { return KeyCommandBindings; }
        }

        #endregion

        #region IControl Members


        public int? TabIndex
        {
            get;
            set;
        }

        #endregion

        #region IControl Members


        public IUitContext Context
        {
            get { return UIT.Context.Current; }
        }

        #endregion

        #region IBindingContainer Members

        private Dictionary<string, Binding> bindings = new Dictionary<string, Binding>();

        public Markup.Binding GetBinding(string propertyName)
        {
            Binding binding;
            bindings.TryGetValue(propertyName, out binding);
            return binding;
        }

        public void SetBinding(string propertyName, Markup.Binding binding)
        {
            Binding originalBinding = GetBinding(propertyName);
            if (originalBinding != null)
                originalBinding.Dispose();
            bindings[propertyName] = binding;
        }

        public bool RemoveBinding(string propertyName)
        {
            Binding originalBinding = GetBinding(propertyName);
            if (originalBinding == null)
                return false;
            originalBinding.Dispose();
            return bindings.Remove(propertyName);

        }

        #endregion


        public void OnPreInit()
        {
            if (PreInit != null)
                PreInit(this, EventArgs.Empty);
        }

        public void OnPostInit()
        {
            if (PostInit != null)
                PostInit(this, EventArgs.Empty);
        }

        public event EventHandler PreInit;

        public event EventHandler PostInit;

        public void OnPreLoad()
        {
            if (PreLoad != null)
                PreLoad(this, EventArgs.Empty);
        }

        bool loaded = false;

        public void OnPostLoad()
        {
            if (!loaded)
            {
                loaded = true;
                if (PostLoad != null)
                    PostLoad(this, EventArgs.Empty);
            }
        }

        public event EventHandler PreLoad;

        public event EventHandler PostLoad;

        public string AclResource
        {
            get;
            set;
        }
    }
}
